#include <chrono>
#include <thread>
#include <windows.h>
#include "napi.h"

// 定义线上安全结构上下文
struct TsfnContext {
    // 请求ID
    std::string id;
    // 本地线程
    std::thread nativeThread;
    //线程安全函数
    Napi::ThreadSafeFunction tsfn;
};

struct ResBody {
  std::string id;
  int status;
  std::string data;
};

void threadEntry(TsfnContext* context) {
    auto callback = [](Napi::Env env, Napi::Function jsCallback, ResBody * body) {
        jsCallback.Call({
          Napi::String::New(env, body->id),
          Napi::Number::New(env, body->status),
          Napi::String::New(env, body->data)
        });
    };
    ResBody res1 = { context->id, 0, "before loop" };
    context->tsfn.BlockingCall(&res1, callback);
    std::this_thread::sleep_for(std::chrono::seconds(3));

    ResBody res2 = { context->id, 1, "after first loop done" };
    context->tsfn.BlockingCall(&res2, callback);
    std::this_thread::sleep_for(std::chrono::seconds(5));

    ResBody res3 = { context->id, 2, "after second loop done" };
    context->tsfn.BlockingCall(&res3, callback);

    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    // 释放线程安全函数
    context->tsfn.Release();
}

//垃圾清理 类似js上下文析构函数
void FinalizerCallback(Napi::Env env,
                       void* finalizeData,
                       TsfnContext* context) {
    //等待本地thread结束
    context->nativeThread.join();
    delete context;
}


// 创建线程安全函数和本地线程
Napi::String DoLongTask(const Napi::CallbackInfo& info) {
    //js引擎环境
    Napi::Env env = info.Env();
    // 构造上下文数据
    auto ctxData = new TsfnContext();
    ctxData->id = info[0].As<Napi::String>();
    // 创建一个线程安全函数
    ctxData->tsfn = Napi::ThreadSafeFunction::New(
            env,                           // Environment
            info[1].As<Napi::Function>(),  // js回调函数
            "TSFN22",                        // 随意名字
            0,                             // 最大队列数
            1,                             // 初始化线程数量
            ctxData,                      // 自定义上下文,
            FinalizerCallback,             // 析构函数
            (void*)nullptr                 // 析构函数 数据
    );
    //创建本地线程
    ctxData->nativeThread = std::thread(threadEntry, ctxData);
    // 函数的终结回调
    return Napi::String::New(env, "sync done");
}

// c++在主进程阻塞
Napi::String DoLongTaskSync(const Napi::CallbackInfo& info) {
    //js引擎环境
    Napi::Env env = info.Env();
    Napi::String reqId = info[0].As<Napi::String>();
    Napi::Function cb = info[1].As<Napi::Function>();

    cb.Call({
        reqId,
        Napi::Number::New(env, 0),
        Napi::String::New(env, "before loop")
    });
    Sleep(1e3 * 3);
     cb.Call({
        reqId,
        Napi::Number::New(env,1),
        Napi::String::New(env, "after first loop done")
    });
    Sleep(1e3 * 5);

    cb.Call({
            reqId,
            Napi::Number::New(env, 2),
            Napi::String::New(env, "after second loop done")
        });
    Sleep(1);


    // 函数的终结回调
    return Napi::String::New(env, "sync done");
}

//DoLongTask
Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports["DoLongTask"] = Napi::Function::New(env, DoLongTask);
    exports["DoLongTaskSync"] = Napi::Function::New(env, DoLongTaskSync);
    return exports;
}

NODE_API_MODULE(addon, Init)
